package com.bwbear.db.splitdb.utils;


import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

/**
 * @author 张照威
 * @date 2020/8/17
 * @mail 865533614@qq.com
 * @describe
 */
public class BeanMapperUtils {


    public static <I, O> List<O> mapToList(List<I> inList, Class<O> outClass) {
        Class<?> inClass = inList.get(0).getClass();
        List<Field> inClassFieldList = Arrays.asList(inClass.getDeclaredFields());
        Map<String, Field> outClassFieldsMap = getOutFieldsMap(outClass);
        List<O> outList = new ArrayList<>();
        inList.stream().forEach(in -> {
            outList.add(mapper(in, inClassFieldList, outClass, outClassFieldsMap));
        });
        return outList;
    }

    private static <I, O> O mapper(I in, List<Field> inClassFieldList, Class<O> outClass, Map<String, Field> outClassFieldsMap) {
        try {
            O out = outClass.getConstructor().newInstance();
            inClassFieldList.stream().filter(f ->
                    outClassFieldsMap.containsKey(f.getName())).forEach(e -> {
                Field outField = outClassFieldsMap.get(e.getName());
                if (e.getType() == outField.getType()) {
                    try {
                        e.setAccessible(true);
                        outField.setAccessible(true);
                        outField.set(out, e.get(in));
                    } catch (IllegalAccessException e1) {
                        e1.printStackTrace();
                    }
                }
            });
            return out;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }


    public static <I, O> O map(I in, Class<O> outClass) {
        Class<?> inClass = in.getClass();
        List<Field> inClassFieldList = Arrays.asList(inClass.getDeclaredFields());
        Map<String, Field> outClassFieldsMap = getOutFieldsMap(outClass);
        O out = mapper(in, inClassFieldList, outClass, outClassFieldsMap);
        return out;
    }

    private static <O> Map<String, Field> getOutFieldsMap(Class<O> outClass) {
        Map<String, Field> outClassFieldsMap = new HashMap<>();
        Field[] outClassFields = outClass.getDeclaredFields();
        for (Field outField : outClassFields) {
            outClassFieldsMap.put(outField.getName(), outField);
        }
        return outClassFieldsMap;
    }
}
